<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>实现Vue2双向绑定</title>
</head>

<body>
  <div id="app">
    <input type="text" id="input" />
    <p id="output"></p>
  </div>
  <script>
    // 实现vue2的双向绑定
    let activeWatcher = null

    class Dep {
      constructor() {
        this.subs = new Set()
      }

      depend() {
        if (activeWatcher) {
          this.subs.add(activeWatcher)
        }
      }

      notify() {
        this.subs.forEach(watcher => watcher.update())
      }
    }


    function defineReactive(obj, key, val) {
      const dep = new Dep()

      Object.defineProperty(obj, key, {
        get() {
          dep.depend()
          return val
        },
        set(newVal) {
          if (val !== newVal) {
            val = newVal
            dep.notify()
          }
        }
      })
    }

    function observe(obj) {
      Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key]))
    }


    class Watcher {
      constructor(fn) {
        this.fn = fn
        this.get()
      }

      get() {
        activeWatcher = this
        this.fn()
        activeWatcher = null
      }

      update() {
        this.get()
      }
    }

  </script>

  <script>

    // 初始化响应式数据
    const data = { text: 'hello' }
    observe(data)

    // 建立渲染函数
    new Watcher(() => {
      document.querySelector('#output').textContent = data.text
    })

    // 模拟 v-model：监听 input 改变 data
    document.querySelector('#input').addEventListener('input', e => {
      data.text = e.target.value
    })

    // 初始赋值 input
    document.querySelector('#input').value = data.text


  </script>
</body>

</html>